﻿using Dapper;
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using static Dapper.SqlMapper;

namespace DAL.Common
{
    // 自定义命名转换策略：处理实体类(PascalCase)与数据库字段(_lower_case_with_underscore)的映射
    public class CustomNamingStrategy : ITypeMap
    {
        private readonly Type _entityType;
        private readonly Dictionary<string, PropertyInfo> _propertyMappings; // 数据库字段 → 实体属性的映射缓存
        private readonly ConstructorInfo _defaultConstructor; // 实体类的无参构造函数

        public CustomNamingStrategy(Type entityType)
        {
            _entityType = entityType ?? throw new ArgumentNullException(nameof(entityType));
            _propertyMappings = BuildPropertyMappings(entityType);
            _defaultConstructor = FindDefaultConstructor(entityType);
        }

        // 构建数据库字段到实体属性的映射字典（预加载提升性能）
        private Dictionary<string, PropertyInfo> BuildPropertyMappings(Type type)
        {
            var mappings = new Dictionary<string, PropertyInfo>(StringComparer.OrdinalIgnoreCase);
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            foreach (var prop in properties)
            {
                // 将实体属性名（如UserName）转换为数据库字段名（如_user_name）
                string dbColumnName = ConvertToDatabaseColumnName(prop.Name);
                if (!mappings.ContainsKey(dbColumnName))
                {
                    mappings[dbColumnName] = prop;
                }
            }

            return mappings;
        }

        // 实体属性名 → 数据库字段名（PascalCase → _lower_case_with_underscore）
        private string ConvertToDatabaseColumnName(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName)) return propertyName;

            var result = new StringBuilder();
            result.Append('_'); // 数据库字段前导下划线
            result.Append(char.ToLower(propertyName[0])); // 首字母小写

            // 处理后续字符，遇到大写字母添加下划线并转为小写
            for (int i = 1; i < propertyName.Length; i++)
            {
                if (char.IsUpper(propertyName[i]))
                {
                    result.Append('_');
                    result.Append(char.ToLower(propertyName[i]));
                }
                else
                {
                    result.Append(propertyName[i]);
                }
            }

            return result.ToString();
        }

        // 数据库字段名 → 实体属性名（_lower_case_with_underscore → PascalCase）
        private string ConvertToEntityPropertyName(string dbColumnName)
        {
            if (string.IsNullOrEmpty(dbColumnName)) return dbColumnName;

            // 移除前导下划线
            string nameWithoutUnderscore = dbColumnName.StartsWith("_")
                ? dbColumnName.Substring(1)
                : dbColumnName;

            // 按下划线分割并转换为PascalCase（如user_name → UserName）
            var parts = nameWithoutUnderscore.Split('_', StringSplitOptions.RemoveEmptyEntries);
            return string.Concat(Array.ConvertAll(parts, part =>
                part.Length > 0 ? char.ToUpper(part[0]) + part.Substring(1).ToLower() : ""));
        }

        // 查找实体类的无参构造函数（Dapper需要用它实例化对象）
        private ConstructorInfo FindDefaultConstructor(Type type)
        {
            return type.GetConstructor(Type.EmptyTypes)
                ?? throw new InvalidOperationException($"实体类 {type.Name} 缺少无参构造函数，无法完成Dapper映射");
        }

        #region ITypeMap接口实现（核心映射逻辑）
        // 查找与数据库列匹配的构造函数（简化实现：优先使用无参构造函数）
        public ConstructorInfo FindConstructor(string[] columnNames, Type[] columnTypes)
        {
            return _defaultConstructor;
        }

        // 获取默认构造函数
        public ConstructorInfo GetConstructor()
        {
            return _defaultConstructor;
        }

        // 查找与数据库列对应的实体属性
        public PropertyInfo GetProperty(string columnName)
        {
            // 优先从缓存映射中查找
            if (_propertyMappings.TryGetValue(columnName, out var prop))
            {
                return prop;
            }

            // 缓存未命中时，动态转换列名并反射查找属性
            string propertyName = ConvertToEntityPropertyName(columnName);
            return _entityType.GetProperty(
                propertyName,
                BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase
            );
        }

        // 处理构造函数参数映射（简化实现：不支持构造函数注入，返回null）
        public ParameterInfo GetConstructorParameter(ConstructorInfo constructor, string columnName)
        {
            return null;
        }

        // 查找显式标记的构造函数（如[ExplicitConstructor]特性标记的）
        public ConstructorInfo FindExplicitConstructor()
        {
            // 若无需显式构造函数，返回null即可
            return null;
        }

        // 接口显式实现：构造函数参数映射（返回IMemberMap）
        IMemberMap ITypeMap.GetConstructorParameter(ConstructorInfo constructor, string columnName)
        {
            // 不支持构造函数参数映射时，返回null
            return null;
        }

        // 获取与数据库列对应的成员映射（属性或字段）
        public IMemberMap GetMember(string columnName)
        {
            var property = GetProperty(columnName);
            return property != null ? new PropertyMemberMap(property) : null;
        }
        #endregion

        // 辅助类：实现IMemberMap接口，包装PropertyInfo
        private class PropertyMemberMap : IMemberMap
        {
            public PropertyMemberMap(PropertyInfo property)
            {
                Property = property;
                Member = property;
                ColumnName = null; // 这里不需要显式列名，因为映射逻辑已在外部处理
            }

            public string ColumnName { get; }
            public MemberInfo Member { get; }
            public PropertyInfo Property { get; }
            public FieldInfo Field => null; // 不处理字段映射
            public ParameterInfo Parameter => null; // 不处理构造函数参数

            public Type MemberType => Property.PropertyType;
        }
    }
}
